package com.edgar.loglib;

import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.util.Date;

/**
 * Created by edgar on 2015/11/14.
 * <p>Custom print utils</p>
 * <p>如果想设置日志存储目录,请在工程的assets目录中配置log_config.properties</p>
 * @see LogConfig
 */
public class LogUtils {
    private static final String TAG = "LogUtils";
    private static final int PROCESS_ID = Process.myPid();;
    private static String sProcessName;
    /**
     * 测试环境设置VERBOSE:全部打印
     * 正式环境选择INFO或者Error级别.
     */
    private static int sLogLevel = Log.VERBOSE;
    private static File sLogDir;
    private static ILog sDefaultLogTask;
    private static ILog sCustomLog = null;
    private static LogConfig sLogConfig;
    private static Context sAppContext;
    private static volatile boolean sIsInit = false;

    private static Handler sLogHandler;
    private static HandlerThread sLogThread;

    /**
     * @see android.util.Log
     * <li>{@link Log#VERBOSE}<li/>
     * <li>{@link Log#DEBUG}<li/>
     * <li>{@link Log#ERROR}<li/>
     * <li>{@link Log#INFO}<li/>
     * <li>{@link Log#WARN}<li/>
     * @param logLevel
     */
    public static void setLogLevel(int logLevel){
        sLogLevel = logLevel;
    }

    /**
     * 获取日志目录
     * @return
     */
    public static File getLogFileDirectory(){
        checkInitialize();
        return  sLogDir;
    }

    /**
     * 获取指定日期的日志文件
     * @param date
     * @return
     */
    public static File getLogFileWitchDate(Date date){
        checkInitialize();
        return new File(sLogDir,Utils.generateFileName(date));
    }

    /**
     * Must call init method
     * @param context
     */
    public static void initialize(Context context){
        if (!sIsInit){
            sAppContext = context.getApplicationContext();
            sProcessName = Utils.getCurrentProcessName(sAppContext);
            sLogConfig = new LogConfig(context);
            sLogDir = new File(Environment.getExternalStorageDirectory(),sLogConfig.getLogPath());
            //需要先看看日志目录存不存在.
            if(!sLogDir.exists()){
                sLogDir.mkdirs();
            }
            sDefaultLogTask = new DefaultWriteLog(sLogDir);
            startLogThread();
            sIsInit = true;
        }
    }

    private static void startLogThread(){
        sLogThread = new HandlerThread(TAG);
        sLogThread.start();
        sLogHandler = new Handler(sLogThread.getLooper());
    }

    public static LogConfig getLogConfig(){
        checkInitialize();
        return sLogConfig;
    }

    public static synchronized void setCustomLogTask(ILog iLog){
        sCustomLog = iLog;
    }

    /**
     * Build log message.
     * @return
     */
    private static LogMessage buildLogMessage(String tag,String message,String logLevel,Throwable throwable){
        checkInitialize();
        if(throwable == null){
            throwable = new Throwable();
        } else {
            message = message+"\n"+Log.getStackTraceString(throwable);
        }
        LogMessage logMessage = new LogMessage();
        logMessage.setLogPrintTime(new Date());
        logMessage.setProcessId(PROCESS_ID);
        logMessage.setProcessName(sProcessName);
        logMessage.setTag(tag);
        logMessage.setThreadId(Thread.currentThread().getId());
        logMessage.setLogLevel(logLevel);
        StackTraceElement[] stackTraceElements = throwable.getStackTrace();
        for (StackTraceElement caller : stackTraceElements){
            String callerClazzName = caller.getClassName();
            if(!LogUtils.class.getName().equals(callerClazzName)){
                String methodName = caller.getMethodName();
                callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf('.') + 1);
                callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf('$') + 1);
                logMessage.setClassName(callerClazzName);
                logMessage.setMessage(message);
                logMessage.setMethodName(methodName);
                logMessage.setLineNum(caller.getLineNumber());
                break;
            }
        }
        return logMessage;
    }

    private static void checkInitialize(){
        if(!sIsInit){
            throw new RuntimeException("sInstance is null,please call LogUtils.initialize(context) method.");
        }
    }

    public static void d(String tag,String msg) {
        d(tag,msg,null);
    }

    public static void d(String tag,String msg, Throwable tr) {
        if(sLogLevel <= Log.DEBUG){
            LogMessage logMessage = buildLogMessage(tag,msg,"D",tr);
            Log.d(tag, msg, tr);
            dumpFile(logMessage);
        }
    }

    public static void e(String tag,String msg) {
        e(tag,msg,null);
    }

    public static void e(String tag,String msg, Throwable tr) {
        if(sLogLevel <= Log.ERROR){
            LogMessage logMessage = buildLogMessage(tag,msg,"E",tr);
            Log.e(tag, msg, tr);
            dumpFile(logMessage);
        }
    }

    public static void i(String tag,String msg) {
        i(tag,msg,null);
    }

    public static void i(String tag,String msg, Throwable tr) {
        if(sLogLevel <= Log.INFO){
            LogMessage logMessage = buildLogMessage(tag,msg,"I",tr);
            Log.i(tag, msg, tr);
            dumpFile(logMessage);
        }
    }

    public static void v(String tag,String msg) {
        v(tag,msg,null);
    }

    public static void v(String tag,String msg, Throwable tr) {
        if(sLogLevel <= Log.VERBOSE){
            LogMessage logMessage = buildLogMessage(tag,msg,"V",tr);
            Log.v(tag, msg, tr);
            dumpFile(logMessage);
        }
    }

    public static void w(String tag,String msg) {
        w(tag,msg,null);
    }

    public static void w(String tag,String msg, Throwable tr) {
        if(sLogLevel <= Log.WARN){
            LogMessage logMessage = buildLogMessage(tag,msg,"W",tr);
            Log.w(tag, msg, tr);
            dumpFile(logMessage);
        }
    }

    public static void wtf(String tag,String msg) {
        wtf(tag,msg,null);
    }

    public static void wtf(String tag,String msg, Throwable tr) {
        if(sLogLevel <= Log.ERROR){
            LogMessage logMessage = buildLogMessage(tag,msg,"WTF",tr);
            Log.wtf(tag, tr);
            dumpFile(logMessage);
        }
    }

    /**
     * 统一的写文件入口
     * @param logMessage
     */
    private static void dumpFile(final LogMessage logMessage){
        sLogHandler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    sDefaultLogTask.onPrintLog(logMessage);
                    //The call custom print.
                    if (sCustomLog != null) {
                        sCustomLog.onPrintLog(logMessage);
                    }
                } catch (IOException e) {
                    //忽视
                }
            }
        });
    }
}